package controllers;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;

import models.ComidaPlan;
import models.EstadoPaciente;
import models.EstadoPlan;
import models.Genero;
import models.Paciente;
import models.Plan;
import models.PorcionPlan;
import models.TemplatePlan;
import models.TipoPlan;
import models.VisibilidadTemplatePlan;
import play.db.Model;
import play.exceptions.TemplateNotFoundException;
import play.mvc.With;

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import controllers.securesocial.SecureSocial;

@With(SecureSocial.class)
public class Plans extends CustomCRUD {
	
	public static void newPlan1(Long pacienteId) throws Exception {
		
		TipoPlan[] tiposPlan = TipoPlan.values();
		
		render(getControllerName() + "/newPlan1.html", pacienteId, tiposPlan);
	}
	
	public static void newPlan2(Long pacienteId, String tiposPlan, Integer caloriasDiarias) throws Exception {
		
		Paciente paciente = (Paciente) getUsuarioLogueado();
		List<TipoPlan> tiposDePlan = parsearTiposPlan(tiposPlan);
		
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		
		if(caloriasDiarias != null && (caloriasDiarias < 500 || caloriasDiarias > 10000)) {
			
			validation.addError("caloriasDiarias", "crud.help.range");
			validation.keep();
			
			newPlan1(pacienteId);
		}
		
		List<TemplatePlan> templatesPlan = new ArrayList<TemplatePlan>();
		
		for (TipoPlan tipo : tiposDePlan) {
			
			// pregunto por id > 1 para que no me traiga el 1, que es el template vacio
			List<TemplatePlan> templatesTipo = TemplatePlan.find("byTipoElikeAndCaloriasDiariasLessThanEqualsAndIdGreaterThan", tipo, caloriasDiarias, 1L).query.getResultList();
			
			for (TemplatePlan templatePlan : templatesTipo) {
				if(templatePlan.getVisibilidad().equals(VisibilidadTemplatePlan.TODOS) // Si es visible para todos
					|| templatePlan.getVisibilidad().equals(VisibilidadTemplatePlan.PACIENTES)  // O si es visible el paciente
						&& templatePlan.getAutor() != null
						&& paciente.getNutricionista() != null
						&& templatePlan.getAutor().getId().equals(paciente.getNutricionista().getId())
						&& EstadoPaciente.CONFIRMADO.equals(paciente.getEstadoPaciente())) { // y el paciente esta comfirmado
					
					templatesPlan.add(templatePlan);					
				}
			}
		}
		
		render(getControllerName() + "/newPlan2.html", type, pacienteId, templatesPlan, caloriasDiarias);
	}
    
	public static void newPlan3(Long pacienteId, Integer caloriasDiarias, Long templatePlanId) throws Exception {
		
        TemplatePlan templatePlan = (TemplatePlan)TemplatePlan.findById(templatePlanId);
        
        Plan nuevoPlan = new Plan((Paciente)Paciente.findById(pacienteId), templatePlan);
        
		Calendar fechaInicio = Calendar.getInstance();
		Calendar fechaFin = Calendar.getInstance();
		fechaFin.add(Calendar.MONTH, 1);
		
		nuevoPlan.setCaloriasDiarias(templatePlan.getCaloriasDiarias());
		nuevoPlan.setFechaInicio(fechaInicio.getTime());
		nuevoPlan.setFechaFin(fechaFin.getTime());
		nuevoPlan.setNombre(templatePlan.getNombre() + "_" + Calendar.getInstance().getTime().getHours() + "-" + Calendar.getInstance().getTime().getMinutes());
		nuevoPlan.setTipo(templatePlan.getTipo());
		
		nuevoPlan.save();
		
		nuevoPlan.setTemporal(Boolean.TRUE); // para que se pueda cancelar en la creación. Si tiene True, en lugar de cancelar, te lo borra todo
		show(nuevoPlan._key().toString(), Boolean.TRUE);
		
	}
	
	public static void agregarPorcionPlan(String planId, Long comidaPlanId, String genero, Integer cantidadPorciones) throws Exception {
		
		ComidaPlan comidaPlan = ComidaPlan.findById(comidaPlanId);
		
		PorcionPlan porcionPlan = comidaPlan.contienePorcionPlanDelGenero(Genero.valueOf(genero));
		
		if(porcionPlan != null) {
			porcionPlan.setCantidadDePorciones(porcionPlan.getCantidadDePorciones() + cantidadPorciones);
		}
		else {
			porcionPlan = new PorcionPlan(Genero.valueOf(genero), cantidadPorciones);
		}
		
		comidaPlan.agregarPorcionPlan(porcionPlan);
		
		comidaPlan.save();
		
		show(planId);
		
    }
	
	public static void eliminarPorcionPlan(String planId, Long porcionId) throws Exception {
		
		PorcionPlan porcionPlan = PorcionPlan.findById(porcionId);
		
		porcionPlan.delete();
		
		show(planId);
		
    }
    
	/** Este metodo es para cuando el paciente cancela el wizard de creacion. Salto al último paso
	 * directamente con los datos que tengo y/o puedo deducir
	 */
	public static void newPlanManual(Long pacienteId, Integer caloriasDiarias) throws Exception {
		
		Integer calorias = (caloriasDiarias == null)? 2000 : caloriasDiarias;
		
		// Le mando el ID = 1 para que hacer referencia al template vacio
		newPlan3(pacienteId, calorias, 1L);
		
    }
    
	/**
	 * Este metodo agarra un String cpon formato JSON y devuelve un array de tipoPlan para
	 * cada uno de los tipos de planes que existen en el string original.
	 * */
    private static List<TipoPlan> parsearTiposPlan(String tiposPlan) {
		
		List<TipoPlan> tiposDePlan = new ArrayList<TipoPlan>();
		
		JsonParser jsonParser = new JsonParser();
		
		Iterator<JsonElement> tiposPlanesIterator = jsonParser.parse(tiposPlan).getAsJsonArray().iterator();
		
		while (tiposPlanesIterator.hasNext()) {
			
			String unTipo = tiposPlanesIterator.next().getAsString();
			List<TipoPlan> tipos = Arrays.asList(TipoPlan.values());
			
			if(tipos.contains(TipoPlan.valueOf(unTipo))) {
				tiposDePlan.add(TipoPlan.valueOf(unTipo));
			}
		}
		
		return tiposDePlan;
	}
    
	public static void list(int page, String search, String searchFields, String orderBy, String order) {
		
		Paciente paciente = (Paciente)getUsuarioLogueado();
		
		Long pacienteId = paciente.id;
		
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		
		if (page < 1) {
			page = 1;
		}
		
		List<Model> objects = type.findPage(page, search, searchFields, orderBy, order, (String) request.args.get("where"));
		
		List<Model> filteredObjects = new ArrayList<Model>();
		
		for (Model model : objects) {
			if (((Plan)model).getPaciente().id.equals(pacienteId)) {
				filteredObjects.add(model);
			}
		}
		
		objects = filteredObjects;
		
		Long count = new Long(objects.size());
		Long totalCount = new Long(objects.size());
		
        try {
            render(type, objects, count, totalCount, page, orderBy, order, pacienteId);
        } catch (TemplateNotFoundException e) {
            render(getControllerName() + "/list.html", type, objects, count, totalCount, page, orderBy, order, pacienteId);
        }
    }
	
	public static void cambiarEstado(Long id) throws Exception {
		
		Plan plan = Plan.findById(id);
		Long userId = plan.getPaciente().getId();
		List<Plan> planesActivos = Plan.findByMismoPacienteActiva(userId);
		
		if (EstadoPlan.INACTIVO.equals(plan.getEstado()) && planesActivos.size() > 0) {
			//tiene al menos un plan activo
			validation.addError("dietas", "Ya tiene asignado un Plan Alimenticio Activo. Por favor, desactive el actual antes de Activar uno nuevo.");
			validation.keep();
		} else {
			plan.cambiarEstado();
			plan.save();
		}
		
		list(0, null, null, null, null);
	}
	
	public static void show(String id, Boolean vieneDeWizard) throws Exception {
		
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		
		Plan object = (Plan)type.findById(id);
		
		notFoundIfNull(object);
		
		if(vieneDeWizard != null && vieneDeWizard) {
			object.setTemporal(vieneDeWizard);
		}
		
		try {
			render(type, object);
		} catch (TemplateNotFoundException e) {
			render(getControllerName() + "/show.html", type, object);
		}
	}
	
	public static void cancelDelete(Long id) {
		
		Plan plan = Plan.findById(id);
		
		plan.delete();
		
		list(0, null, null, null, null);
		
	}
	
}
